package role

import (
	"context"
	"database/sql"
	"go-zero-project/common/excption"
	"go-zero-project/services/user/rpc/constans"
	"go-zero-project/services/user/rpc/internal/mapper"
	"go-zero-project/services/user/rpc/internal/mapper/bo"
	"go-zero-project/services/user/rpc/internal/mapper/entity"
	"go-zero-project/services/user/rpc/internal/svc"
	"go-zero-project/services/user/rpc/pb"
	"gorm.io/gorm"

	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateRoleLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateRoleLogic {
	return &UpdateRoleLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *UpdateRoleLogic) UpdateRole(in *pb.UpdateRoleReq) (*pb.UpdateRoleResp, error) {
	// 1.check role name and role id
	roleMapper := mapper.NewRoleMapper()
	roleBO := bo.SysRoleBO{RoleName: in.RoleName, NeRoleId: in.RoleId}
	selectCount, err := roleMapper.SelectCount(l.svcCtx.DBEngin, roleBO)
	if err != nil {
		return nil, err
	}
	if selectCount > 0 {
		return nil, excption.NewErrCode(constans.RoleNameIsExistError)
	}
	// 2.begin  Transaction
	txInsertErr := l.txUpdate(in, roleMapper)
	if txInsertErr != nil {
		return nil, txInsertErr
	}
	return &pb.UpdateRoleResp{RoleId: in.RoleId}, nil
}

func (l *UpdateRoleLogic) txUpdate(in *pb.UpdateRoleReq, roleMapper *mapper.RoleMapper) error {
	roleEntity := entity.SysRoleEntity{RoleId: in.RoleId, DeptId: in.DeptId,
		RoleName: in.RoleName, Remark: in.RoleRemark}
	txInsertErr := l.svcCtx.DBEngin.Transaction(func(tx *gorm.DB) error {
		// 2.1修改角色信息
		roleUpdateErr := roleMapper.Update(tx, roleEntity)
		if roleUpdateErr != nil {
			return roleUpdateErr
		}
		// 2.2 修改角色与菜单的关系
		if len(in.MenuIdArr) < 1 {
			return excption.NewErrCode(constans.RoleNoSelectMenu)
		}
		roleMenuInsertErr := l.updateRoleMenu(tx, in)
		if roleMenuInsertErr != nil {
			return roleMenuInsertErr
		}
		// 2.3.修改数据权限的关系
		updateRoleDeptErr := l.updateRoleDept(in)
		if updateRoleDeptErr != nil {
			return updateRoleDeptErr
		}
		return nil
	})
	return txInsertErr
}

func (l *UpdateRoleLogic) updateRoleDept(in *pb.UpdateRoleReq) error {
	// 2.3.1 删除之前的关系
	deptMapper := mapper.NewRoleDeptMapper()
	deleteRoleDeptErr := deptMapper.DeleteRoleDept(l.svcCtx.DBEngin, []int64{in.RoleId})
	if deleteRoleDeptErr != nil {
		return deleteRoleDeptErr
	}
	if len(in.DeptIdArr) < 1 {
		return nil
	}
	// 2.3.2 再次进行绑定
	var roleDeptArr []entity.SysRoleDeptEntity
	for _, v := range in.DeptIdArr {
		roleDept := entity.SysRoleDeptEntity{RoleId: in.RoleId,
			DeptId: v}
		roleDeptArr = append(roleDeptArr, roleDept)
	}
	deptRoleInsertId, deptRoleInsertErr := deptMapper.BatchInsert(l.svcCtx.DBEngin, roleDeptArr)
	if deptRoleInsertErr != nil {
		return deptRoleInsertErr
	}
	logx.Infof("保存数据权限的关系,id:%s", deptRoleInsertId)
	return nil
}

func (l *UpdateRoleLogic) updateRoleMenu(tx *gorm.DB, in *pb.UpdateRoleReq) error {
	// 2.2.1 先删除之前的绑定关系
	menuMapper := mapper.NewRoleMenuMapper()
	deleteRoleMenu := menuMapper.DeleteRoleMenu(l.svcCtx.DBEngin, []int64{in.RoleId})
	if deleteRoleMenu != nil {
		return deleteRoleMenu
	}
	// 2.2.2 再次新增 新的绑定关系
	var roleMenuArr []entity.SysRoleMenuEntity
	for _, v := range in.MenuIdArr {
		roleMenu := entity.SysRoleMenuEntity{RoleId: sql.NullInt64{Int64: in.RoleId, Valid: true},
			MenuId: sql.NullInt64{
				Int64: v, Valid: true}}
		roleMenuArr = append(roleMenuArr, roleMenu)
	}
	roleMenu, roleMenuInsertErr := mapper.NewRoleMenuMapper().BatchInsert(tx, roleMenuArr)
	if roleMenuInsertErr != nil {
		return roleMenuInsertErr
	}
	logx.Infof("保存角色与菜单的关系,id:%s", roleMenu)
	return nil
}
